package com.coldlz.mmp.proxy.handlerclient;

import com.coldlz.mmp.proxy.Interceptor;
import com.coldlz.mmp.proxy.ProxyInfo;
import com.coldlz.mmp.proxy.UserContext;
import com.coldlz.mmp.proxy.WebSocketHandshakeRequest;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;
import java.util.Map;

public class ClientProxyHttpHandler extends ChannelDuplexHandler {
    private static final Logger log = LoggerFactory.getLogger(ClientProxyHttpHandler.class);
    private final UserContext userContext;
    private final Channel clientChannel;

    public ClientProxyHttpHandler(UserContext userContext) {
        this.userContext = userContext;
        this.clientChannel = userContext.getClientChannel();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        userContext.setRemoteChannel(ctx.channel());
        userContext.getProxyInfo().setRemoteAddress(ctx.channel().remoteAddress().toString());
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        SocketAddress socketAddress = ctx.channel().remoteAddress();
//        log.info("断开连接-->{}", socketAddress);
        super.channelInactive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object obj) {
        if (obj instanceof FullHttpResponse r) {
            proxyFullHttpResponse(r);
        } else if (obj instanceof ByteBuf msg) {
            //log.info("直接转发数据。。。");
            proxyByteBuf(msg);// 直接转发的时候会走这个流程//io/netty/netty-codec-http/4.1.108.Final/netty-codec-http-4.1.108.Final-sources.jar!/io/netty/handler/codec/http/HttpObjectDecoder.java:530
        } else if (obj instanceof HttpObject httpObject) {
            proxyHttpObject(httpObject);
        } else {
            throw new RuntimeException("未知类型");
        }
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        if (msg instanceof WebSocketHandshakeRequest handshakeRequest) {
            for (Map.Entry<String, String> header : handshakeRequest.headers()) {
                System.out.println(header.getKey() + "  " + header.getValue());
            }
        }
        super.write(ctx, msg, promise);
    }

    private void proxyHttpObject(HttpObject httpObject) {
        if (httpObject instanceof HttpMessage httpMessage) {
            proxyHttpMessage(httpMessage);
        } else if (httpObject instanceof HttpContent httpContent) {
            Runnable callback = null;
            if (httpObject instanceof LastHttpContent lastHttpContent) {
                // 说明数据包已经发送完毕，这里将进行记录
//                callback = userContext::close;
            }
            proxyHttpContent(httpContent, callback);
        } else {
            throw new RuntimeException("类型转换异常");
        }
    }

    private void proxyHttpContent(HttpContent httpContent, Runnable closeRunnable) {
        HttpContent newHttpContent = httpContent.copy();

        ChannelFuture channelFuture = clientChannel.writeAndFlush(httpContent);
        channelFuture.addListener((ChannelFutureListener) future -> {
            if (!future.isSuccess() && future.cause() != null) {
                boolean active = clientChannel.isActive();
                boolean open = clientChannel.isOpen();
                boolean registered = clientChannel.isRegistered();
                log.warn("active={} open={} registered={}", active, open, registered);
                log.error("发送数据异常2 1.. ", future.cause());
            }
            userContext.getRecordInterceptor().recordResponseHttpContent(newHttpContent, userContext.getProxyInfo());
//            if (newHttpContent.refCnt() > 0) {
//                ReferenceCountUtil.release(newHttpContent);
//            }
            if (closeRunnable != null) {
                closeRunnable.run();
            }
        });
    }

    private void proxyHttpMessage(HttpMessage httpMessage) {
        clientChannel.writeAndFlush(httpMessage).addListener((ChannelFutureListener) future -> {
            if (!future.isSuccess() && future.cause() != null) {
                boolean active = clientChannel.isActive();
                boolean open = clientChannel.isOpen();
                boolean registered = clientChannel.isRegistered();
                log.warn("active={} open={} registered={}", active, open, registered);
                log.error("发送数据异常2 2.. ", future.cause());
            }
            userContext.getRecordInterceptor().recordResponseHttpMessage(httpMessage, userContext.getProxyInfo());
        });
    }

    private void proxyByteBuf(ByteBuf msg) {
        ByteBuf copy = msg.copy();
        int len = msg.readableBytes();
        byte[] bytes = new byte[len];
        msg.readBytes(bytes);

        ChannelOutboundInvoker ctx;
        if (!userContext.isDirectForward()) {
            ctx = clientChannel/*.pipeline().context(SslHandler.class)*/;
        } else {
            ctx = clientChannel;
        }
        ctx.writeAndFlush(copy).addListener((ChannelFutureListener) future -> {
            if (!future.isSuccess()) {
                ProxyInfo info = userContext.getProxyInfo();
                String originalContent = new String(info.getOriginalContent());

                System.out.println(bytes[0] + " " + bytes[1] + " " + bytes[2]);
                System.out.println(new String(bytes, 3, bytes.length - 3));
                log.error("发送数据异常2 3.. originalContent = {}", originalContent, future.cause());
            }
        });
    }

    private void proxyFullHttpResponse(FullHttpResponse r) {
        FullHttpResponse newResponse = r;
        ProxyInfo info = userContext.getProxyInfo();
        for (Object item : userContext.getInterceptors()) {
            if (item instanceof Interceptor interceptor) {
                newResponse = interceptor.modifyResponse(newResponse, info);
            }
        }
        if (newResponse == r) {
            newResponse = r.copy();
        }

        FullHttpResponse newResponseFinal = newResponse;
        clientChannel.writeAndFlush(newResponse).addListener((ChannelFutureListener) future -> {
            if (!future.isSuccess() && future.cause() != null) {
                log.error("发送数据异常1..", future.cause());
            }
            if (ReferenceCountUtil.refCnt(newResponseFinal.content()) > 0) {
                ReferenceCountUtil.safeRelease(newResponseFinal.content());
            }
//            userContext.close();
        });
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("发生异常信息{}", ctx.name(), cause);
        userContext.close();// 通道发生异常 关闭
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
    }

}